package com.geniusk.mqtt.utils;

import com.geniusk.mqtt.TopicChannelSession;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Slf4j
public class MqttUtil {

    /**
     * 订阅推送
     */
    public static void sendToMqtt(String topicName, String data){
        ByteBuf payload = Unpooled.copiedBuffer(data.getBytes());
        ByteBuf mqttMessage = createMqttPublishMessage(topicName, payload);
        // 从全局用户Channel关系中获取接受方的channel
        List<Channel> topicChannelList = TopicChannelSession.getChannelListByTopicName(topicName);
        if (topicChannelList != null){
            for (Channel channel : topicChannelList){
                //writeAndFlush会将ByteBuf的引用释放refCnt会减去1,使用retain加1
                mqttMessage.retain();
                channel.writeAndFlush(mqttMessage);
            }
            mqttMessage.release();
        }
    }

    // 构建MQTT PUBLISH消息的方法
    private static ByteBuf createMqttPublishMessage(String topic, ByteBuf payload) {
        byte[] topicBytes = topic.getBytes();
        int variableHeaderLength = topicBytes.length + 2; // 2 bytes for topic length
        int payloadLength = payload.readableBytes();
        int remainingLength = variableHeaderLength + payloadLength;

        ByteBuf buf = Unpooled.buffer(1 + getRemainingLengthSize(remainingLength) + remainingLength);

        // 固定头部
        buf.writeByte(0b00110000); // PUBLISH packet type and flags

        // 剩余长度
        writeRemainingLength(buf, remainingLength);

        // 可变头部
        buf.writeShort(topicBytes.length);
        buf.writeBytes(topicBytes);

        // 有效负载
        buf.writeBytes(payload);

        return buf;
    }

    private static void writeRemainingLength(ByteBuf buf, int length) {
        do {
            byte digit = (byte) (length % 128);
            length /= 128;
            if (length > 0) {
                digit |= 0x80;
            }
            buf.writeByte(digit);
        } while (length > 0);
    }

    private static int getRemainingLengthSize(int length) {
        int size = 0;
        do {
            length /= 128;
            size++;
        } while (length > 0);
        return size;
    }
}
